package graph.editor;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RectangularShape;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JToolBar;

import observable.ObservableAutomaton;
import automaton.NotDeterministiTransitionException;
import automaton.NotDeterministicInitialStateException;
import automaton.UnknownInitialStateException;

public class GraphFrame extends JFrame {
	GraphComponent component;
	private FramesController controller;

	public GraphFrame(FramesController controller) {
		this.controller = controller;

		component = new GraphComponent();
		component.setForeground(Color.BLACK);
		component.setBackground(Color.WHITE);
		component.setOpaque(true);
		component.setPreferredSize(new Dimension(1000, 1000));
		JScrollPane scrollPane = new JScrollPane(component);

		JMenuBar menuBar = new JMenuBar();
		setJMenuBar(menuBar);
		JMenu menu = new JMenu(GraphEditor.MENU_FILE);
		menuBar.add(menu);
		JMenu menu_run = new JMenu("Run");
		menuBar.add(menu_run);

		// initial load and save
		final JFileChooser jFc = new JFileChooser();
		jFc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
		jFc.setFileHidingEnabled(false);
		jFc.setAcceptAllFileFilterUsed(false);

		final JColorChooser jCc = new JColorChooser();
		createMenuItem(menu, GraphEditor.MENU_ITEM_NEW, new ActionListener() {
			public void actionPerformed(ActionEvent ev) {
				
				GraphFrame.this.controller.createFrame();
				GraphFrame.this.controller.deleteFrame(GraphFrame.this);
			}
		});
		// component.currentEdge
		createMenuItem(menu, GraphEditor.MENU_ITEM_CLOSE, new ActionListener() {
			public void actionPerformed(ActionEvent ev) {
				GraphFrame.this.controller.deleteFrame(GraphFrame.this);
			}
		});

		createMenuSeparator(menu);
		// add load , save ,run
		createMenuItem(menu, GraphEditor.MENU_ITEM_LOAD, new ActionListener() {
			public void actionPerformed(ActionEvent ev) {

				try {
					int returnVal = jFc.showOpenDialog(GraphFrame.this);
					if (returnVal == JFileChooser.CANCEL_OPTION) {
						return;
					}
					if (returnVal == JFileChooser.APPROVE_OPTION) {

						File file = null;
						file = jFc.getSelectedFile();
						Data data = null;
						if (file.exists()) {
							System.out.println(file.getAbsolutePath());
							FileInputStream fileIn = new FileInputStream(file
									.getAbsolutePath());
							ObjectInputStream input = new ObjectInputStream(
									fileIn);

							data = (Data) input.readObject();
							input.close();
							fileIn.close();

							component.edges = data.getEdges();
							component.vertices = data.getVertices();
							System.out.println(component.edges.size());
							for (Edge e : component.edges) {
								TextField label = new TextField();
								System.out.println(e.textField.getText());
								component.loadLabel(e);
								label.setText(e.textField.getText());
								component.repaint();
							}

							System.out.println(data.getEdges().size());
						}

					}

				} catch (Exception e) {
					JOptionPane.showMessageDialog(null,
							GraphEditor.DIALOG_OPEN_ERROR);
					e.printStackTrace();
				}
			}
		});

		createMenuItem(menu, GraphEditor.MENU_ITEM_SAVE, new ActionListener() {
			public void actionPerformed(ActionEvent ev) {

				try {
					int returnVal = jFc.showSaveDialog(GraphFrame.this);
					if (returnVal == JFileChooser.CANCEL_OPTION) {
						return;
					}
					if (returnVal == JFileChooser.APPROVE_OPTION) {

						File file = null;
						file = jFc.getSelectedFile();

						System.out.println(file.getCanonicalPath());
						System.out.println(file.getName() + "." + "dat");
						Data data = new Data(component.edges,
								component.vertices);
						FileOutputStream fileOut = new FileOutputStream(file
								.getAbsolutePath() + "." + "dat", true);
						ObjectOutputStream output = new ObjectOutputStream(
								fileOut);

						output.writeObject(data);
						output.flush();
						output.close();
						fileOut.close();
						JOptionPane.showMessageDialog(null,
								GraphEditor.DIALOG_SAVE);
						System.out.println("write successfulkl");
						System.out.println(data.getEdges().size());
						System.out.println(data.getVertices().size());
					}

				} catch (IOException i) {
					i.printStackTrace();
					JOptionPane.showMessageDialog(null,
							GraphEditor.DIALOG_SAVE_ERROR);
				}

			}
		});

		createMenuSeparator(menu);
		createMenuItem(menu, GraphEditor.MENU_ITEM_QUIT, new ActionListener() {
			public void actionPerformed(ActionEvent ev) {
				GraphFrame.this.controller.quit();
			}
		});

		createMenuItem(menu_run, GraphEditor.MENU_ITEM_COLOR,
				new ActionListener() {
					public void actionPerformed(ActionEvent ev) {

						jCc.getSelectionModel();
						Color nColor = JColorChooser.showDialog(
								GraphFrame.this, "COLOR", getForeground());
						component.setForeground(nColor);
						component.repaint();
					}
				});
		createMenuItem(menu_run, GraphEditor.MENU_ITEM_RUN,
				new ActionListener() {
					public void actionPerformed(ActionEvent ev) {

						try {
							RunFrame rf = new RunFrame(component);
							final ObservableAutomaton<String> ob = rf.run();
							ob.addObserver(component);
							//
							String word = JOptionPane
									.showInputDialog("Enter input");
							if (word != null && word.trim().length() > 0) {
								final String[] arr = convertString(word);
								Runnable run = new Runnable() {

									@Override
									public void run() {
										component.paintState(ob.initialState());
										if (ob.recognize(arr)) {
											JOptionPane
													.showMessageDialog(
															null,
															GraphEditor.STRING_WORD_RECOGNIZE);
										} else {
											JOptionPane.showMessageDialog(null,
													GraphEditor.STRING_WORD);
										}
									}
								};
								Thread t = new Thread(run);
								t.start();
							} else {
								JOptionPane.showConfirmDialog(null,
										GraphEditor.STRING_INPUT_WORD);
							}

						} catch (NotDeterministiTransitionException
								| NotDeterministicInitialStateException
								| UnknownInitialStateException e) {
							System.out.println(e.getMessage());
						}

					}

				});
		createMenuSeparator(menu_run);
		createMenuItem(menu_run, GraphEditor.MENU_ITEM_ABOUT,
				new ActionListener() {
					public void actionPerformed(ActionEvent ev) {
						JOptionPane.showMessageDialog(null,
								GraphEditor.STRING_ABOUT);
					}
				});
		createMenuItem(menu_run, GraphEditor.MENU_ITEM_HELP,
				new ActionListener() {
					public void actionPerformed(ActionEvent ev) {
						GraphFrame.this.controller.quit();
					}
				});
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				GraphFrame.this.controller.deleteFrame(GraphFrame.this);
			}
		});

		JToolBar toolbar = new JToolBar();
		toolbar.setBackground(Color.LIGHT_GRAY);
		toolbar.setLayout(new GridLayout(0, 1));
		addShapeButton(toolbar, new Ellipse2D.Double(0, 0, 10, 10),
				"Small Circle");
		addShapeButton(toolbar, new Ellipse2D.Double(0, 0, 20, 20),
				"Big Circle");
		addShapeButton(toolbar, new Rectangle2D.Double(0, 0, 10, 10),
				"Small Square");
		addShapeButton(toolbar, new Rectangle2D.Double(0, 0, 20, 20),
				"Big Square");

		Container contentPane = getContentPane();
		contentPane.add(toolbar, BorderLayout.WEST);
		contentPane.add(scrollPane, BorderLayout.CENTER);
	}

	private void addShapeButton(JToolBar toolbar,
			final RectangularShape sample, String name) {
		JButton button = new JButton(name);
		// button.setBackground(Color.);
		button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				component.setVertexSample(sample);
			}
		});
		toolbar.add(button);
	}

	private void createMenuItem(JMenu menu, String name, ActionListener action) {
		JMenuItem menuItem = new JMenuItem(name);
		menuItem.addActionListener(action);
		menu.add(menuItem);
	}

	private void createMenuSeparator(JMenu menu) {
		JSeparator separator = new JSeparator();
		separator.setForeground(Color.lightGray);
		menu.add(separator);
	}

	public String[] convertString(String s)

	{
		String[] arr = new String[s.length()];
		for (int i = 0; i < s.length(); i++) {
			arr[i] = String.valueOf(s.charAt(i));
		}
		return arr;

	}

}
